package com.njuse.jvmfinal.memory.jclass;

import com.njuse.jvmfinal.classloader.classfileparser.ClassFile;
import com.njuse.jvmfinal.classloader.classfileparser.FieldInfo;
import com.njuse.jvmfinal.classloader.classfileparser.MethodInfo;
import com.njuse.jvmfinal.classloader.classfileparser.constantpool.ConstantPool;
import com.njuse.jvmfinal.memory.jclass.runtimeConstantPool.RuntimeConstantPool;
import com.njuse.jvmfinal.runtimestructure.Jarray;
import com.njuse.jvmfinal.runtimestructure.Jframe;
import com.njuse.jvmfinal.runtimestructure.Jlink;
import com.njuse.jvmfinal.runtimestructure.Jthread;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class JClass {
    private short accessFlags;
    private String name;
    private String superClassName;
    private String[] interfaceNames;
    private RuntimeConstantPool runtimeConstantPool;
    private Field[] fields;
    private Method[] methods;
    private int preference; //1-user,2-ext,3-boot
    private JClass superClass;
    private JClass[] interfaces;
    private int instanceSlotCount;
    private int staticSlotCount;
    private Object[] statics;
    private boolean loadingok=false;
    private boolean initok=false;
    private JClass component=null;
    private int flag=0;
    private boolean isarray=false;

    public JClass(ClassFile classFile) {
        this.accessFlags = classFile.getAccessFlags();
        this.name = classFile.getClassName();
        if (!this.name.equals("java/lang/Object")) {
            // index of super class of java/lang/Object is 0
            this.superClassName = classFile.getSuperClassName();
        } else {
            this.superClassName = "";
        }
        this.interfaceNames = classFile.getInterfaceNames();
        this.fields = parseFields(classFile.getFields());
        this.methods = parseMethods(classFile.getMethods());
        this.runtimeConstantPool = parseRuntimeConstantPool(classFile.getConstantPool());
    }
    
    //[L型数组类或者[[I型数组类构造方法
    public JClass(String name,JClass com) {
    	this.isarray=true;
    	this.name=name;
    	this.component=com;
    }
   

    //[I型数组类构造方法
    public JClass(String name,String com) {
    	this.isarray=true;
    	this.name=name;
    	switch (com) {
    	  case "I":{
    	           this.flag=10;
    	           break;}
    	  case "J":{
	           this.flag=11;
	           break;}
    	  case "S":{
	           this.flag=9;
	           break;}
    	  case "B":{
	           this.flag=8;
	           break;}
    	  case "D":{
	           this.flag=7;
	           break;}
    	  case "F":{
	           this.flag=6;
	           break;}
    	  case "C":{
	           this.flag=5;
	           break;}
    	  case "Z":{
	           this.flag=4;
	           break;}
    	}
    	this.component=null;        
    	}
  
    //得到数组类的一个对象，link是链表
    public Jarray getinstance(Jlink link) {
    	Jarray array=null;
    	if (flag!=0) {
    	 array=new Jarray(link,flag,null,this);
    	}else {
    	 array=new Jarray(link,0,this.component,this);
    	}
    	return array;
    }
    
    
    private Field[] parseFields(FieldInfo[] info) {
        int len = info.length;
        fields = new Field[len];
        for (int i = 0; i < len; i++) {
            fields[i] = new Field(info[i], this);
        }
        return fields;
    }

    private Method[] parseMethods(MethodInfo[] info) {
        int len = info.length;
        methods = new Method[len];
        for (int i = 0; i < len; i++) {
            methods[i] = new Method(info[i], this);
        }
        return methods;
    }

    private RuntimeConstantPool parseRuntimeConstantPool(ConstantPool cp) {
        return new RuntimeConstantPool(cp, this);
    }
    
    public void setStaticSlotCount(int num) {
    	this.staticSlotCount=num;
    	this.statics=new Object[num];
    }
    
    public Method findmethod(String name, String descriptor, boolean isStatic) {
        Method[] methods = this.getMethods();
        for (int i=0;i<methods.length;i++) {
        	if (methods[i].getDescriptor().equals(descriptor)) {
        		if (methods[i].getName().equals(name)) {
        			if (((methods[i].getAccessFlags()&AccessFlags.ACC_STATIC)!=0)==isStatic) {
        				return methods[i];
        			}
        		}
        	}
        }
        return null;
    }
    
    public void init(Jthread thread) {
    	JClass t=this;
    	while (t!=null) {
    		if (t.initok==true) return;
    		Method clinit=t.findmethod("<clinit>","()V", true);
    		if (clinit!=null) {
    		      Jframe frame = new Jframe(thread, clinit, clinit.getMaxStack(), clinit.getMaxLocal());
    		      thread.push(frame);
    		}
    		t.initok=true;
    		t=t.getSuperClass();
    	}
    }
}
